package br.com.foxinline.manager.criar;

import br.com.foxinline.enums.TipoLocalidade;
import br.com.foxinline.modelo.Anexo;
import br.com.foxinline.modelo.Bairro;
import br.com.foxinline.modelo.Cidade;
import br.com.foxinline.modelo.Coordenada;
import br.com.foxinline.modelo.Endereco;
import br.com.foxinline.modelo.Estado;
import br.com.foxinline.modelo.Grupo;
import br.com.foxinline.modelo.Localidade;
import br.com.foxinline.modelo.Prefeitura;
import br.com.foxinline.servico.AnexoServico;
import br.com.foxinline.servico.BairroServico;
import br.com.foxinline.servico.CidadeServico;
import br.com.foxinline.servico.GrupoServico;
import br.com.foxinline.servico.LocalidadeServico;
import br.com.foxinline.servico.PrefeituraServico;
import br.com.foxinline.servico.UsuarioServico;
import br.com.foxinline.util.ArquivoUtilitario;
import br.com.foxinline.util.Conexao;
import br.com.foxinline.util.Msg;
import java.beans.Transient;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import org.primefaces.context.RequestContext;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.event.map.MarkerDragEvent;
import org.primefaces.event.map.OverlaySelectEvent;
import org.primefaces.event.map.PointSelectEvent;
import org.primefaces.event.map.StateChangeEvent;
import org.primefaces.model.map.DefaultMapModel;
import org.primefaces.model.map.LatLng;
import org.primefaces.model.map.Marker;

/**
 *
 * @author laverson
 */
@ViewScoped
@ManagedBean
public class ManagerMapaLocalidade implements Serializable {

    @EJB
    BairroServico bairroServico;
    @EJB
    LocalidadeServico localidadeServico;
    @EJB
    UsuarioServico usuarioServico;
    @EJB
    GrupoServico grupoServico;
    @EJB
    CidadeServico cidadeServico;
    @EJB
    PrefeituraServico prefeituraServico;
    @EJB
    AnexoServico anexoServico;
    private Localidade localidade;
    private List<Localidade> localidades;
    private DefaultMapModel mapModel;
    private DefaultMapModel mapModelEditar;
    private String centroMapa;
    private String centroMapaEditar;
    private int zoomLevelMapa;
    private Bairro bairro;
    private Cidade cidade;
    private boolean connect;
    private ArquivoUtilitario arquivoUtilitario;
    private Marker markerEditar;
    private String tipoMapa = "ROADMAP";
    private int activeTabIndex;
    private boolean desabilitarAdicionar;

    @PostConstruct
    public void init() {
        iniciarLocalidade();

        this.centroMapa = prefeituraServico.getCentroMapa();
        this.zoomLevelMapa = prefeituraServico.getZoomMapa();

        this.localidades = new ArrayList<Localidade>();
        this.activeTabIndex = 0;

        this.bairro = new Bairro();
        iniciarCidade();

        this.mapModel = new DefaultMapModel();
        this.mapModelEditar = new DefaultMapModel();

        this.arquivoUtilitario = new ArquivoUtilitario();

        this.desabilitarAdicionar = false;

        isConnected();

        plotar();
    }

    public void iniciarLocalidade() {
        this.localidade = new Localidade();
        this.localidade.setCoordenada(new Coordenada());
        this.localidade.setAnexo(getAnexoPadrao());
    }

    @Transient
    private void isConnected() {
        if (prefeituraServico.find().getDesabilitarMapas()) {

            this.connect = false;
        } else if (!Conexao.isInternetReachable()) {

            this.connect = false;
            Msg.messagemWarn("Não foi possível estabelecer uma conexão com a Internet.");
        } else {
            this.connect = true;
        }
    }

    public void plotar() {
        this.mapModel = new DefaultMapModel();
        LatLng coord;
        this.localidades = localidadeServico.findAll();

        for (Localidade local : this.localidades) {
            Coordenada c = local.getCoordenada();
            coord = new LatLng(c.getLat(), c.getLog());
            this.mapModel.addOverlay(new Marker(coord, local.getNome(), "", iconPath(local.getTipoLocal())));
        }
    }

    public void handlePointClick(PointSelectEvent event) {

        iniciarLocalidade();

        LatLng latLng = event.getLatLng();

        this.localidade.setCoordenada(new Coordenada(latLng.getLat(), latLng.getLng()));
    }

    public void gravar() {
        if (this.localidade.getId() != null) {
            atualizar();
        } else {
            salvar();
        }

        this.activeTabIndex = 0;
        this.desabilitarAdicionar = false;
    }

    public void salvar() {
        try {
            this.mapModel.addOverlay(getNovoMarker());

            if (this.localidade.getAnexo().equals(getAnexoPadrao())) {
                this.localidade.setAnexo(null);
            }

            localidadeServico.save(this.localidade);
            this.localidades.add(this.localidade);
            iniciarLocalidade();

            Msg.messagemInfo(Msg.SuccessFull);

            init();
        } catch (Exception e) {
            System.err.println(e);
            Msg.messagemError(Msg.Failure);
        }
    }

    public void atualizar() {
        try {
            this.localidade.getCoordenada().setLat(this.markerEditar.getLatlng().getLat());
            this.localidade.getCoordenada().setLog(this.markerEditar.getLatlng().getLng());

            if (this.localidade.getAnexo().getId() == null) {

                if (this.localidade.getAnexo().equals(getAnexoPadrao())) {
                    this.localidade.setAnexo(null);
                }
            }

            localidadeServico.update(this.localidade);
            Msg.messagemInfo(Msg.SuccessFull);

            iniciarLocalidade();
            this.mapModel = new DefaultMapModel();
            plotar();

        } catch (Exception e) {
            System.err.println(e);
            Msg.messagemError(Msg.Failure);
        }
    }

    public void cancelar() {
        iniciarLocalidade();
        iniciarCidade();
        this.activeTabIndex = 0;
        this.desabilitarAdicionar = false;
    }

    public void editar() {
        if (this.localidade.getAnexo() == null) {
            this.localidade.setAnexo(getAnexoPadrao());
        }

        LatLng latLng = new LatLng(this.localidade.getCoordenada().getLat(), this.localidade.getCoordenada().getLog());
        this.markerEditar = getNovoMarker();
        this.markerEditar.setDraggable(true);
        this.markerEditar.setLatlng(latLng);

        this.centroMapaEditar = latLng.getLat() + "," + latLng.getLng();

        this.mapModelEditar = new DefaultMapModel();
        this.mapModelEditar.addOverlay(this.markerEditar);

        this.cidade = localidade.getBairro().getCidade();

        RequestContext.getCurrentInstance().execute("dlg.show()");
    }

    public void excluir() {
        try {
            this.localidadeServico.delete(this.localidade);
            init();
            Msg.messagemInfo(Msg.SuccessFull);
        } catch (Exception e) {
            System.err.println(e);
            Msg.messagemInfo(Msg.Failure);
        }
    }

    public void onMarkerDragEditar(MarkerDragEvent event) {
        this.markerEditar = event.getMarker();

        for (Marker m : this.mapModel.getMarkers()) {
            if (this.markerEditar.getId().equals(m.getId())) {
                m.setLatlng(this.markerEditar.getLatlng());
                break;
            }
        }

        List<Marker> markers = this.mapModelEditar.getMarkers();
        this.mapModelEditar = new DefaultMapModel();

        for (Marker m : markers) {
            m.setDraggable(true);
            m.setLatlng(m.getLatlng());
            m.setIcon(iconPath(this.localidade.getTipoLocal()));

            this.mapModelEditar.addOverlay(m);
        }
    }

    public void onStateChange(StateChangeEvent event) {
        this.zoomLevelMapa = event.getZoomLevel();
        this.centroMapa = event.getCenter().getLat() + ", " + event.getCenter().getLng();
    }

    public void onStateChangeEditar(StateChangeEvent event) {
        onStateChange(event);
    }

    public void onMarkerSelect(OverlaySelectEvent event) {
        Marker marker = (Marker) event.getOverlay();

        for (Localidade local : this.localidades) {
            if (local.getCoordenada().getLat().equals(marker.getLatlng().getLat()) && local.getCoordenada().getLog().equals(marker.getLatlng().getLng())) {
                this.localidade = local;
                break;
            }
        }
    }

    @Transient
    private Marker getNovoMarker() {
        Coordenada coord = this.localidade.getCoordenada();

        LatLng latLng = new LatLng(coord.getLat(), coord.getLog());
        Marker marker = new Marker(latLng, this.localidade.getNome(), "icon.png", iconPath(this.localidade.getTipoLocal()));

        return marker;
    }

    private String iconPath(TipoLocalidade tipoLocal) {
        String path = "/media/images/";
        String iconPath;

        if (tipoLocal.equals(TipoLocalidade.POLICIA)) {
            iconPath = getRequestURL().concat(path.concat("policia.png"));
        } else if (tipoLocal.equals(TipoLocalidade.EDUCACAO)) {
            iconPath = getRequestURL().concat(path.concat("educacao.png"));
        } else if (tipoLocal.equals(TipoLocalidade.HOTEL)) {
            iconPath = getRequestURL().concat(path.concat("hotel.png"));
        } else if (tipoLocal.equals(TipoLocalidade.LAZER)) {
            iconPath = getRequestURL().concat(path.concat("lazer.png"));
        } else {
            iconPath = getRequestURL().concat(path.concat("saude.png"));
        }

        return iconPath;
    }

    @Transient
    public List<TipoLocalidade> getTipoLocal() {
        List<TipoLocalidade> items = Arrays.asList(TipoLocalidade.values());
        return items;
    }

    public void selectCidade(SelectEvent event) {
        this.cidade = (Cidade) event.getObject();
    }

    @Transient
    private String getRequestURL() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
        String requestURL = request.getRequestURL().toString();
        String url = requestURL.substring(0, requestURL.lastIndexOf("/"));
        return url;
    }

    public void adicionarAnexo(FileUploadEvent event) throws IOException {
        try {
            Anexo anexo = arquivoUtilitario.adicionarArquivo(event.getFile().getContents(), event.getFile().getFileName(), event.getFile().getContentType());

            localidade.setAnexo(anexo);

        } catch (FileNotFoundException e) {

            System.err.println(e);
            Msg.messagemError(Msg.Failure);

        } catch (SQLException e) {

            System.err.println(e);
            Msg.messagemError(Msg.Failure);
        }
    }

    public void removerAnexo() {
        System.err.println("excluir anexo");

        try {
            File file = new File(this.localidade.getAnexo().getUrl().concat(this.localidade.getAnexo().getNome()));
            this.arquivoUtilitario.excluirArquivo(file);
            this.localidade.setAnexo(getAnexoPadrao());
        } catch (FileNotFoundException ex) {
            Logger.getLogger(ManagerMapaLocalidade.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Transient
    private Anexo getAnexoPadrao() {
        return this.anexoServico.getAnexoPadrao();
    }

    /**
     * Permite que os markers já adicionados possam ser editados/removidos. Operações estas que só podem ser executadas
     * por usuários que não forem contribuintes
     *
     * @return <b>true</b> caso o usuário esteja habilitado para realizar as operações, <b>false</b> caso contrário
     */
    public boolean habilitarBotaoInfoWindow() {
        List<Grupo> grupos = usuarioServico.getCurrentUser().getGrupos();

        if (grupos.size() == 1 && grupos.contains(grupoServico.find(2L))) {
            return false;
        }

        return true;
    }

    /**
     * Permite que novos markers sejam adicionados no mapa
     */
    public void habilitarAdicionar() {
        desabilitarAdicionar = false;
    }

    /**
     * Desabilita o botão de remover o anexo
     *
     * @return <b>false<b/> caso o anexo não seja o padrão, <b>true</b> caso contrário
     */
    public boolean desabilitarBotaoRemover() {

        if (this.localidade.getAnexo().equals(getAnexoPadrao())) {
            return true;
        }

        return false;
    }

    private void iniciarCidade() {

        Prefeitura prefeitura = prefeituraServico.getPrefeituraAtual();

        if (prefeitura.getEndereco() != null) {
            Endereco endereco = prefeitura.getEndereco();

            if (endereco.getBairroDne() != null && endereco.getBairroDne() != null) {

                if (endereco.getBairroDne().getCidade() != null) {
                    this.cidade = endereco.getBairroDne().getCidade();
                } else {

                    this.cidade = new Cidade();
                    this.cidade.setEstado(new Estado());
                }
            }
        }
    }

    public List<Bairro> autocompleteBairro(String query) {
        return bairroServico.autocomplete(query, this.cidade);
    }

    public Localidade getLocalidade() {
        return localidade;
    }

    public void setLocalidade(Localidade localidade) {
        this.localidade = localidade;
    }

    public List<Localidade> getLocalidades() {
        return localidades;
    }

    public void setLocalidades(List<Localidade> localidades) {
        this.localidades = localidades;
    }

    public String getCentroMapa() {
        return centroMapa;
    }

    public void setCentroMapa(String centroMapa) {
        this.centroMapa = centroMapa;
    }

    public DefaultMapModel getMapModel() {
        return mapModel;
    }

    public void setMapModel(DefaultMapModel mapModel) {
        this.mapModel = mapModel;
    }

    public Bairro getBairro() {
        return bairro;
    }

    public void setBairro(Bairro bairro) {
        this.bairro = bairro;
    }

    public boolean isConnect() {
        return connect;
    }

    public void setConnect(boolean connect) {
        this.connect = connect;
    }

    public int getZoomLevelMapa() {
        return zoomLevelMapa;
    }

    public void setZoomLevelMapa(int zoomLevelMapa) {
        this.zoomLevelMapa = zoomLevelMapa;
    }

    public DefaultMapModel getMapModelEditar() {
        return mapModelEditar;
    }

    public void setMapModelEditar(DefaultMapModel mapModelEditar) {
        this.mapModelEditar = mapModelEditar;
    }

    public Marker getMarkerEditar() {
        return markerEditar;
    }

    public void setMarkerEditar(Marker markerEditar) {
        this.markerEditar = markerEditar;
    }

    public String getTipoMapa() {
        return tipoMapa;
    }

    public void setTipoMapa(String tipoMapa) {
        this.tipoMapa = tipoMapa;
    }

    public String getCentroMapaEditar() {
        return centroMapaEditar;
    }

    public void setCentroMapaEditar(String centroMapaEditar) {
        this.centroMapaEditar = centroMapaEditar;
    }

    public int getActiveTabIndex() {
        return activeTabIndex;
    }

    public void setActiveTabIndex(int activeTabIndex) {
        this.activeTabIndex = activeTabIndex;
    }

    public boolean isDesabilitarAdicionar() {
        return desabilitarAdicionar;
    }

    public void setDesabilitarAdicionar(boolean desabilitarAdicionar) {
        this.desabilitarAdicionar = desabilitarAdicionar;
    }

    public Cidade getCidade() {
        return cidade;
    }

    public void setCidade(Cidade cidade) {
        this.cidade = cidade;
    }
}
